C++ 虚析构函数的使用
===============================

不熟悉 C++ 的程序员会遇到一个问题，什么时候需要用虚析构函数？ `When to use virtual destructors? <https://stackoverflow.com/questions/461203/when-to-use-virtual-destructors>`__ 解答了这个问题。

简单地说，就是如果需要通过基类指针析构对象的话，就需要虚析构函数，否则只有基类的析构函数会被调用，导致派生类中的使用的资源不会被释放。

那么什么时候会用到基类指针呢？通常是在使用多态类的时候。这就是为什么通常有虚函数的类需要有虚析构函数。但是在非多态类中，如果程序员要用基类指针调虚构函数的话，同样会有内存泄漏的问题，因此同样需要虚析构函数。例如::

  #include <vector>
  
  class Base
  {
  	public:
  	virtual ~Base() {}
  };
  
  class Derive: public Base
  {
  	std::vector<int> v;
  	public:
  	Derive(): v(4, 0) {}
  };
  
  int main()
  {
  	Base *p = new Derive;
  	delete p;
  }

如果 Base 的析构函数不是虚函数，就会导致 Derive 类中的 vector 发生内存泄漏，使用 address sanitizer 可以证实这点。当然了，ASAN 会报一个 new-delete-type-mismatch 错误，表明调用了不正确的析构函数，设置 ``ASAN_OPTIONS=new_delete_type_mismatch=0`` 运行程序，就会报出内存泄漏。

不过，对于非多态类，程序员一般不会通过基类指针释放一个对象，因此不需要定义析构函数为虚函数。

此外，Stack Overflow 中有一个回答很有意思，如果使用 ``shared_ptr<Base>(new Derive)`` 的话，那么共享指针释放资源的时候，调用的是派生类的析构函数。通过查看 ``shared_ptr`` 的实现，可以发现 ``shared_ptr<_Tp>(_Yp *p)`` 实际上是一个函数模板，通过反汇编也可以看出这点。这个函数模板使得编译器可以检查类的派生关系，并使得产生的共享指针对象中能保存其中裸指针的实际类型信息。
